package lcmpt;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import javax.swing.JOptionPane;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;

import org.marc4j.marc.Record;

import de.dnb.basics.Misc;
import de.dnb.basics.applicationComponents.FileUtils;
import de.dnb.basics.applicationComponents.StreamUtils;
import de.dnb.basics.applicationComponents.StringUtils;

public class Controller {

	private static final String LCMP_ARCHIVE = "/docs/LCMPTvocab_141011.mrc";

	private static final String LCMPT_WEB_ADRESS =
			"http://classificationweb.net/LCMPT/LCMPTvocab_141011.mrc.zip";

	private static final String LCGFT_ARCHIVE = "/docs/lcgft.mrc";

	View view;

	Model model;

	private InputStream inputStream;

	class MyTreeSelectionListener implements TreeSelectionListener {
		@Override
		public void valueChanged(final TreeSelectionEvent event) {
			final TreePath treePath = event.getPath();
			final Object pathComponent = treePath.getLastPathComponent();
			if (!(pathComponent instanceof DefaultMutableTreeNode))
				return;
			DefaultMutableTreeNode treeNode =
					(DefaultMutableTreeNode) pathComponent;
			String name = treeNode.toString();
			String text = getRecordInfo(name);
			view.setInfo(text);
		}
	}

	/**
	 * 
	 * @param name
	 * @return		info oder leerer String
	 */
	public String getRecordInfo(String name) {
		Record record = model.getRecord(name);
		if (record == null)
			return "";
		String infoText =
				"<h1>" + LCMPTMarcUtils.getPreferredName(record) + " ("
						+ record.getControlNumber() + ")" + "</h1>";
		infoText += LCMPTMarcUtils.getSynonymsAsHTML(record);
		infoText += LCMPTMarcUtils.getOBBAsHTML(record);
		infoText += LCMPTMarcUtils.getUBBAsHTML(model.getUBB(name));
		infoText += LCMPTMarcUtils.getSourcesAsHTML(record);
		infoText += LCMPTMarcUtils.getExplanatoriesAsHTML(record);
		infoText += LCMPTMarcUtils.getTracingNotesAsHTML(record);
		infoText += "<br>" + LCMPTMarcUtils.getRecordAsHTML(record);
		return infoText;
	}

	class ComboHyperListener implements ActionListener, HyperlinkListener {
		@Override
		public void actionPerformed(ActionEvent e) {
			String name = view.getSelectedName();
			if (!StringUtils.isNullOrEmpty(name)) {
				showPaths(name);
			}
		}

		@Override
		public void hyperlinkUpdate(HyperlinkEvent e) {
			if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
				String name = Misc.getAuthority(e);
				if (name == null || name.isEmpty()) {
					return;
				}
				showPaths(name);
			}
		}

		/**
		 * @param name
		 */
		private void showPaths(String name) {
			Collection<DefaultMutableTreeNode> nodes = model.getNodes(name);
			// wenn der Link falsch ist:
			if (nodes == null || nodes.isEmpty())
				return;
			view.collapseTree();
			String s = "";

			MarkedTreeNodeRenderer textTreeNodeRenderer =
					new MarkedTreeNodeRenderer(nodes);
			view.setTreeRenderer(textTreeNodeRenderer);
			Collection<TreeNode[]> paths = model.getPaths(name);
			for (Iterator<TreeNode[]> iterator = paths.iterator(); iterator
					.hasNext();) {
				TreeNode[] treeNodes = iterator.next();
				TreePath path = new TreePath(treeNodes);
				view.expandTree(path);
				List<TreeNode> treeList =
						new LinkedList<>(Arrays.asList(treeNodes));
				treeList.remove(0);
				s += StringUtils.concatenate(" \u2192 ", treeList);
				if (iterator.hasNext())
					s += "\n";

			}
			view.expandTree(null);
			view.setPaths(s);
		}
	}

	class LoadLcmptArchive implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			try {
				setModelToStream(LCMP_ARCHIVE);
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}
	}

	class LoadLcmptWeb implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			try {
				setModelToStream(LCMPT_WEB_ADRESS);
			} catch (IOException e1) {
				JOptionPane.showMessageDialog(null, e1, "Keine Verbindung zu "
						+ LCMPT_WEB_ADRESS + " möglich",
						JOptionPane.ERROR_MESSAGE);

				e1.printStackTrace();
			}
		}
	}
	
	class LoadLcgftArchive implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			try {
				setModelToStream(LCGFT_ARCHIVE);
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}
	}

	public Controller() throws IOException {
		view = new View();
		view.addTreeSelectionListener(new MyTreeSelectionListener());
		view.addComboBoxListener(new ComboHyperListener());
		view.setLinkListener(new ComboHyperListener());
		view.addLcmptAusArchivListener(new LoadLcmptArchive());
		view.addLcmptAusNetzListener(new LoadLcmptWeb());
		view.addLcgftAusArchivListener(new LoadLcgftArchive());
		setModelToStream(LCMP_ARCHIVE);
	}

	/**
	 * @throws IOException
	 */
	public void setNewModel(String path) throws IOException {
		model = new Model(inputStream, path);
		MutableTreeNode treenode = model.getTheTree();
		view.setTree(treenode);
		view.setNames(model.getNames());

	}

	/**
	 * @throws IOException
	 */
	private void setModelToStream(String path) throws IOException {
		if (path.startsWith("http")) {
			inputStream = StreamUtils.getInputStreamFromWeb(path);

		} else if (path.startsWith("/")) {
			inputStream = this.getClass().getResourceAsStream(path);
		}
		if (path.endsWith(FileUtils.ZIP_ENDING)) {
			inputStream =
					StreamUtils
							.getInputStreamOfFirstFileInZipContainer(inputStream);
		}
		setNewModel(path);
	}

	/**
	 * @param args
	 * @throws FileNotFoundException
	 */
	public static void main(String[] args) throws IOException {
		new Controller();

	}

}
